1. Field of the Invention
Methods and apparatuses consistent with the present invention relate to executing an instruction of a Java virtual machine, and more particularly, to executing an instruction of a Java virtual machine in which bytecode executed in a Java virtual machine is transformed into a second code using 16-bit memory elements, thereby considerably improving the speed of executing instructions.
2. Description of the Related Art
Although Java programming language has rapidly proliferated as a standard object-oriented programming language since its advent in the mid-1990s, it has several disadvantages, including a lower execution speed than the C programming language or the C++ programming language. In order to speed up the execution of the Java programming language, a dynamic code generation system, such as a Java virtual machine adopting a just-in-time (JIT) compiler, and a static code generation system, such as a Java virtual machine adopting an ahead-of-time (AOT) compiler, have been developed.
A Java platform consists of a Java virtual machine and a plurality of classes. Each class consists of information corresponding to a data structure of the class, field information, and method information. Execution code of a method is written in bytecodes independent of a hardware device or an operating system.
Conventional Java virtual machines can be classified into interpreter-type Java virtual machines, JIT compiler-type Java virtual machines, interpreter-and-JIT compiler-type Java virtual machines, and AOT compiler-type Java virtual machines according to the types of their respective execution engines.
An interpreter-type Java virtual machine interprets a plurality of bytecodes of a method to be executed one by one, and executes an application program of the method.
A JIT compiler-type Java virtual machine compiles the bytecodes of the method to obtain machine codes dependent upon a Java platform, and executes the machine codes to execute the application program of the method.
FIG. 1 is a diagram illustrating a structure of a conventional Java class file.
Referring to FIG. 1, the Java class file includes a class or interface definition and is comprised of various attributes, field information, method information and so on that are defined in the class. The method information defines a byte stream, which is called a bytecode and can be executed in the interpreter. This bytecode can be obtained from compiling a file (e.g., a file having an extension of “java”) containing a Java source language statement.
The bytecode is similar to a program module ready for execution because the bytecode is executed within a computer one byte at a time. However, the instructions of the bytecode are actual instructions transmitted to the logical and abstract Java virtual machine. The bytecode can be compiled again by the JIT compiler so that the bytecode can be compatible with a particular system platform. This also ensures that the byte code is interpreted by one byte only once, thereby accelerating the execution speed of the Java program.
FIG. 2 illustrates a bytecode to be executed in a conventional Java virtual machine.
Referring to FIG. 2, the instructions of the bytecode are composed of an operand and an opcode, both of which have a size of one byte to discriminate performed operations. One opcode may include several operands. Both the opcode and each operand are stored in the unit of one byte, so that they are represented as consecutive bytes in order to represent the operands having a size of one or more bytes. For example, a 16-bit value consists of two consecutive bytes, and a 32-bit value consists of four consecutive bytes.
In FIG. 2, the first line denotes the hexadecimal values of the actual bytecode, and the second line denotes the bytecode divided into opcodes and operands.
FIG. 3 is a flowchart for explaining a method of executing each instruction code performed by a conventional Java interpreter.
An application class is loaded by a class loader of a Java virtual machine and goes through a linking process and an initialization process, and then associated information is stored in a data structure within a runtime system, and the method is executed by the execution engine such as an interpreter or a JIT compiler.
In a typical interpreter, the bytecode is executed in the manner shown in FIG. 3. When a method is invoked in the interpreter, a program counter indicating the bytecode of the method is incremented (S310). Next, it is determined whether the bytecode of the method is the last bytecode (S320). If it is determined that the bytecode of the method is not the last bytecode (NO in operation S320), a one-byte opcode is fetched (S330). Subsequently, the control goes to a handler corresponding to the fetched one-byte opcode using a switch statement in the program (S340), so that the handler is executed (S350). This process is repeated as many times as necessary depending on the size of the bytecode, and then the interpreting process for the method is terminated.
The process shown in FIG. 5 can be represented with a pseudo-code as follows:
Loop {  Op = *pc++;  switch (Op) {    case op_1:      // op_1's implementation      break;    case op_2:      // op_2's implementation      break;    case op_3:      // op_3's implementation      break;    ...     }
In the handler for the respective opcodes, if the data size of the operand required by the opcode is larger than one byte, the values of the operand are stored in consecutive bytes. Thus, the consecutive bytes are reconstructed into one significant value through an OR operator and a Shift operator according to each bit. For example, in a central processing unit (CPU) using the “little-endian” format, if operands required by a certain opcode A are in subsequent bytes byte1, byte2, byte3 and byte4, then byte4 represents the first bit to the eighth bit of a 32-bit value to be logically indicated, byte3 represents the ninth bit to the sixteenth bit of the 32-bit value to be logically indicated, byte2 represents the seventeenth bit to the twenty-fourth bit of the 32-bit value to be logically indicated, and byte1 represents the twenty-fifth bit to the thirty-second bit of the 32-bit value to be logically indicated.
Therefore, the 32-bit value actually required by the opcode A can be obtained by an operation like “(byte1<<24)|(byte2<<16)|(byte3<<8)|byte4”. In the existing Java virtual machine, processes for combining such operands occur whenever the method is executed.
For the operand, when the data size of the operand is greater than one byte, the operand will be arranged in consecutive bytes, and the consecutive bytes will be reconstructed through the OR operator and the Shift operator according to each bit whenever the method is executed. This process may function as considerable overhead when the Java program is executed. Therefore, there is a need to improve the performance of the Java virtual machine by overcoming these restraints.